package itsm.isperp.framework.service;

import itsm.isperp.framework.collection.tree.ITreeNode;
import itsm.isperp.framework.core.context.ContextHolder;
import itsm.isperp.framework.data.domain.DataRequest;
import itsm.isperp.framework.data.mybatis.dao.TreeNodeMapper;
import itsm.isperp.framework.utils.HibernateUUIDGenerator;
import itsm.isperp.framework.utils.TreeNodeUtils;
import itsm.isperp.framework.web.request.JqGridFilterRuleOp;
import itsm.isperp.framework.web.request.JqGridRequest;
import itsm.isperp.framework.web.response.ResultMessage;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Table;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;

/**
 * 
 * 树形节点的抽象服务
 * 
 * @author lizx
 * @date 2013-2-16
 * @version V1.0
 */
public abstract class TreeNodeService<T extends ITreeNode> extends
		BaseService<T> {

	@Override
	public abstract TreeNodeMapper<T> getRepository();

	/**
	 * 删除一个菜单实体，并且同时删除其所有的子节点（根据路径同时删除子节点）
	 */
	@Override
	public ResultMessage delete(String id) {
		T m = this.getRepository().findOne(id);

		if (m != null) {
			// 利用泛型获取class
			@SuppressWarnings("unchecked")
			Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
					.getGenericSuperclass()).getActualTypeArguments()[0];

			this.getRepository().deleteByClass(id, clazz);
			this.getRepository().deleteByTreenodePath(m);

			rebuildTree();

			return ResultMessage.success();
		} else {
			return ResultMessage.failure("无法删除不存在的节点！");
		}
	}

	public <S extends T> int saveOrUpdate(S entity, HttpServletRequest req) {
		Assert.notNull(entity, "对象不能为空");
		return this.saveOrUpdate(entity);
	}

	@Override
	public <S extends T> int saveOrUpdate(S entity) {

		// 在同一个父节点下不能存在相同名字的子节点
		if (entity == null || entity.getName() == null)
			throw new NullArgumentException("节点名称不能为空");

		int c = this.getRepository().countByParentId(entity.getName(),
				entity.getParentId(), entity.getClass());

		if (StringUtils.isEmpty(entity.getId())
				|| this.getRepository().existsByClass(entity.getId(),
						entity.getClass()) == null) {

			if (StringUtils.isEmpty(entity.getId()))
				entity.setId(HibernateUUIDGenerator.generate());
			if (c > 0)
				throw new RuntimeException("在同一个父节点下不能存在相同名字的子节点");

			if (StringUtils.isEmpty(entity.getParentId())) {
				entity.setTreenodeNamePath("/" + entity.getName() + "/");
				entity.setTreenodePath("/" + entity.getId() + "/");
				entity.setParentId("");
			}

			int result = this.getRepository().save(entity);
			this.rebuildTree();
			return result;
		} else {

			if (c > 1)
				throw new RuntimeException("在同一个父节点下不能存在相同名字的子节点");

			ITreeNode pEntity = this.getRepository().findOne(
					entity.getParentId());

			if (pEntity == null)
				pEntity = TreeNodeUtils.creatRootTreenode(entity.getClass());

			T oldEntity = this.getRepository().findOne(entity.getId());

			entity.setTreenodePath(oldEntity.getTreenodePath() == null ? ""
					: oldEntity.getTreenodePath());
			entity.setTreenodeNamePath(oldEntity.getTreenodeNamePath() == null ? ""
					: oldEntity.getTreenodeNamePath());
			this.getRepository().update(entity);

			this.rebuildTree();

			return 1;
		}
	}

	public List<T> getTree(DataRequest request) {
		List<T> all = this.getRepository().findAllByRequest(request)
				.getContent();
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];

		return TreeNodeUtils.parseAndAddRootFormList(clazz, all, true);
	}

	/**
	 * 根据树形路径查询部门列表
	 * 
	 * @param treenodePath
	 *            树形节点路径
	 * @return 列表
	 */
	public List<T> findByTreenodePath(String treenodePath) {
		DataRequest request = new JqGridRequest();
		request.addFilterRule("treenode_path", JqGridFilterRuleOp.bw,
				treenodePath);
		request.isPageable(false);
		request.setSort("order_num", Direction.ASC);

		return this.findAll(request);
	}

	/**
	 * 根据树形路径查询部门列表
	 * 
	 * @param treenodePath
	 *            树形节点路径
	 * @return 列表
	 */
	public void deleteByTreenodePath(String treenodePath) {

		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
		this.getRepository().deleteByTreenodePathAndClass(treenodePath, clazz);
	}

	/**
	 * 获取树形列表
	 * 
	 * @param parentId
	 *            父节点
	 * @return
	 */
	public List<T> getChildren(String parentId, boolean showRoot) {

		String[] columns = { "id", "name", "parent_id", "treenode_path",
				"leaf", "treenode_name_path", "open" };

		DataRequest request = new JqGridRequest().setSelectColumns(columns)
				.isPageable(false).setSort("order_num", Direction.ASC);
		List<T> tree = null;
		if (StringUtils.isNotEmpty(parentId)) {
			request.addFilterRule("parent_id", JqGridFilterRuleOp.eq, parentId);
			tree = this.getRepository().findAllByRequest(request).getContent();
		} else {
			request.addFilterRule("parent_id", JqGridFilterRuleOp.isnull,
					parentId);
			tree = this.getRepository().findAllByRequest(request).getContent();

			for (T t : tree) {
				if (t.isOpen()) {
					DataRequest request2 = new JqGridRequest()
							.setSelectColumns(columns).isPageable(false)
							.setSort("order_num", Direction.ASC);
					request2.addFilterRule("parent_id", JqGridFilterRuleOp.eq,
							t.getId());
					t.setChildren(this.getRepository()
							.findAllByRequest(request2).getContent());
				}
			}

		}
		if (parentId == null && showRoot) {
			Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
					.getGenericSuperclass()).getActualTypeArguments()[0];
			T root = TreeNodeUtils.creatRootTreenode(clazz);
			List<T> l = new ArrayList<>();
			root.setChildren(tree);
			l.add(root);
			return l;
		}
		return tree;
	}

	/**
	 * 获取树形列表
	 * 
	 * @param parentId
	 *            父节点
	 * @return
	 */
	public List<T> getTree(String parentId) {
		String[] columns = { "id", "name", "parent_id", "treenode_path",
				"leaf", "treenode_name_path", "open" };

		return getTree(parentId, columns);
	}

	public List<T> getTree(String parentId, String... selectColumns) {

		return getTree(parentId, true, selectColumns);
	}

	public List<T> getTree(String parentId, boolean showRoot,
			String... selectColumns) {
		DataRequest request = new JqGridRequest()
				.setSelectColumns(selectColumns).isPageable(false)
				.setSort("order_num", Direction.ASC);

		if (StringUtils.isNotEmpty(parentId)) {

			T p = this.findOne(parentId);
			request.addFilterRule("treenode_path", JqGridFilterRuleOp.bw,
					p.getTreenodePath());
		}
		List<T> tree = this.getRepository().findAllByRequest(request)
				.getContent();

		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];

		return TreeNodeUtils.parseAndAddRootFormList(clazz, tree, showRoot);
	}

	/**
	 * 取得整个的树形列表　
	 * 
	 * @return　树形列表
	 */
	public List<T> getTree() {
		return getTree("");
	}

	/**
	 * 取得整个的树形列表　
	 * 
	 * @return　树形列表
	 */
	public void rebuildTree() {
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		Table table = clazz.getAnnotation(Table.class);
		String sql = "call sp_treenode_rebuild('" + table.name() + "')";

		jdbcTemplate.update(sql);

	}

}
